﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;
using System.Net.Sockets;
using Reborn_Server;
using System.Xml;
using Reborn_Server.App1AppHandler;
using System.IO;
using System.Collections;
using System.Data.SqlClient;
using System.Reflection;
using Reborn_WorldServer;
using Reborn_WorldServer.App1AppHandler;


namespace App1AppHandler
{
    public class Character : CreatureBase
    {
        //Data For Client
        public int UserID = -1;
        public string Gender = "";

        //Communication Object
        public ClientSocketData ClientSocket;

        public Timer Timer_Respawn = new Timer(10 * 60 * 1000);

        private Timer Timer_AI = new Timer();

        public delegate void TimerElapsedHandler(object sender);
        //Event that fires when characters round timer elapses (for spells that need to wait until the round is complete)
        public event TimerElapsedHandler RoundElapsed; 

        //Character Round Timer, We set IsRunning = true whenever the timer starts
        private Timer Timer_Round = new Timer();
        public double Timer_Round_Interval
        {
            get { return Timer_Round.Interval; }
            set { Timer_Round.Interval = value; }
        }
        public void Timer_Round_Start() 
        {
            lock (Timer_Round)
            {
                if (_Timer_Round_IsRunning == true)
                    throw new Exception("Player Move Timer Already Running");

                Timer_Round.Start();
                _Timer_Round_IsRunning = true;
            }
        }
        //Tracks if the round timer is running
        private bool _Timer_Round_IsRunning = false;
        //Read only property to tell us if the round timer is running
        public bool Timer_Round_IsRunning
        {
            get 
            {
                lock (Timer_Round)
                {
                    return _Timer_Round_IsRunning;
                }
            }
        }

        public int ExitSeconds = 0;
        public Timer Timer_Exit = new Timer(1000);

        private Timer Timer_Drop = new Timer(1000 * 30);
        private object timerDropLock = new object();
        private bool timerDropStarted = false;
        public void startDropTimer()
        {
            lock (timerDropLock)
            {
                if (timerDropStarted == true)
                    return;

                timerDropStarted = true;
                Timer_Drop.Start();
            }
        }


        public Timer Timer_AutoSave = new Timer(1000 * 60 * 2);

        public BeltManager beltManager;
        public EquipmentManager equipManager;
        public BankManager bankManager;
        public PetManager petManager;
        public SpellManager spellManager;
        public WeaponSkillManager weaponSkillManager;
        public SkillManager skillManager;
        public BagManager bagManager;
        public FriendsManager friendsManager;
        public ChatChannelManager chatChannelManager;
        public RecipieManager recipieManager;

        public TradeData tradeData;

        public string currentColor
        {
            get
            {
                if (ImageURL.IndexOf("Green") > -1)
                {
                    return "Green";
                }
                else if (ImageURL.IndexOf("Blue") > -1)
                {
                    return "Blue";
                }
                else if (ImageURL.IndexOf("Red", ImageURL.Length - 5) > -1)
                {
                    return "Red";
                }
                else if (ImageURL.IndexOf("Purple") > -1)
                {
                    return "Purple";
                }
                else if (ImageURL.IndexOf("White") > -1)
                {
                    return "White";
                }
                else if (ImageURL.IndexOf("Yellow") > -1)
                {
                    return "Yellow";
                }
                else if (ImageURL.IndexOf("Orange") > -1)
                {
                    return "Orange";
                }
                else if (ImageURL.IndexOf("Black") > -1)
                {
                    return "Black";
                }

                return "";
            }
        }
        private List<CharacterColorOverride> colorOverrides = new List<CharacterColorOverride>();
        public void getColorOverrides()
        {
            colorOverrides.Clear();

            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_ImageColorOverrides_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", ID);

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                CharacterColorOverride cco = new CharacterColorOverride();

                cco.color = SDR["Color"].ToString();
                cco.imageName = SDR["ImageName"].ToString();

                if (SDR["CorpseImageName"] != DBNull.Value)
                    cco.corpseImageName = SDR["CorpseImageName"].ToString();

                colorOverrides.Add(cco);
            }

            SDR.Close();
            SDR.Dispose();

            MyCon.Close();
            MyCon.Dispose();
        }
        public CharacterColorOverride getColorOverride(string color)
        {
            foreach (CharacterColorOverride cco in colorOverrides)
            {
                if (cco.color.ToLower() == color.ToLower())
                {
                    return cco;
                }
            }
            return null;
        }

        //This tracks input from users for requests that require approval (Portal spells, bind spells, etc)
        private long pendingInputCounter = 0;
        private List<PendingUserInput> pendingInputs = new List<PendingUserInput>();
        public long addPendingInput (PendingUserInput pendingInput)
        {
            lock (pendingInputs)
            {
                pendingInputCounter++;
                pendingInputs.Add(pendingInput);
            }
            return pendingInputCounter;
        }
        public bool removePendingInput(PendingUserInput pendingInput)
        {
            lock (pendingInputs)
            {
                return pendingInputs.Remove(pendingInput);
            }
        }
        public void processPendingInputResult(long pendingInputId, string choice)
        {
            lock (pendingInputs)
            {
                foreach (PendingUserInput pendingInput in pendingInputs)
                {
                    if (pendingInput.id == pendingInputId)
                    {
                        pendingInput.processResult(choice);
                        break;
                    }
                }
            }
        }
        public void cancelAllPendingInput()
        {
            lock (pendingInputs)
            {
                while (pendingInputs.Count > 0)
                    pendingInputs[0].cancel();
            }
        }



        public CorpseCharacter myCorpse = null;

        public bool showTips = true;
        public bool GM = false;

        public int BindMapID;
        public int BindMapX;
        public int BindMapY;

        public int LastCheckPointMapID;
        public int LastCheckPointMapX;
        public int LastCheckPointMapY;

        //Constructor add timer handlers & turn timer autoreset to false
        public Character(AppHandler2 appHandler)
            : base(appHandler)
        {
            Timer_Respawn.AutoReset = false;
            Timer_Respawn.Elapsed += new ElapsedEventHandler(Timer_Respawn_Elapsed);

            Timer_Round.AutoReset = false;
            Timer_Round.Elapsed += new ElapsedEventHandler(Timer_Round_Elapsed);

            Timer_Drop.AutoReset = false;
            Timer_Drop.Elapsed += new ElapsedEventHandler(Timer_Drop_Elapsed);

            Timer_Exit.AutoReset = false;
            Timer_Exit.Elapsed += new ElapsedEventHandler(Timer_Exit_Elapsed);

            Timer_AI.AutoReset = false;
            Timer_AI.Elapsed += new ElapsedEventHandler(Timer_AI_Elapsed);

            Timer_AutoSave.AutoReset = false;
            Timer_AutoSave.Elapsed += new ElapsedEventHandler(Timer_AutoSave_Elapsed);
        }

        //TODO: Clean this up
        //Currently only used by teleport when changing servers, the transfer will remove a busy counter, 
        //So since teleport is not an action that sets busy, we need to add a counter. 
        public void addBusyCounter()
        {
            SetBusy(true);
        }
        public void removeBusyCounter()
        {
            SetBusy(false);
        }

        public void ressurectionFailureHandler(string error)
        {
            Managers.GameHandler.Resurrect(this, -1, -1, -1, 100, true);
        }
        public void ressurectionPreTransfer()
        {
            Managers.GameHandler.Resurrect(this, -1, -1, -1, 100, false);
            
            //Add a busy counter, the transfer will assume they moved or performed some action so will un-busy them
            SetBusy(true);
        }

        private bool aiIsRunning = false;
        public void StartAI()
        {
            lock (Timer_AI)
            {
                IAIBuff aiBuff = buffManager.GetAIBuff();

                if (aiIsRunning == true || aiBuff == null)
                    return;

                aiIsRunning = true;
                SetBusy(true);

                Timer_AI.Interval = aiBuff.runAI();
                Timer_AI.Start();
            }
        }
        private void Timer_AI_Elapsed(object source, ElapsedEventArgs e)
        {
            lock (Timer_AI)
            {
                IAIBuff aiBuff = buffManager.GetAIBuff();

                if (aiBuff == null)
                {
                    SetBusy(false);
                    aiIsRunning = false;
                    return;
                }

                if (buffManager.IsStunned() == true)
                    Timer_AI.Interval = 3000;
                else
                    Timer_AI.Interval = aiBuff.runAI();

                Timer_AI.Start();
            }
        }


        //will not let HP < 0 OR HP > MaxHP
        //Starts Exit Timer
        public override int HP {
            set {
                if (value != base.HP)
                {
                    if (value < 0)
                        value = 0;
                    else if (value > MaxHP)
                        value = MaxHP;

                    if (value < base.HP)
                    {
                        ExitSeconds = 30;
                        Timer_Exit.Stop();
                        Timer_Exit.Start();
                    }

                    base.HP = value;
                    if (base.HP < 1)
                    {
                        //TODO: Figure out how pet manager was null (Server crash on character death)
                        if (petManager != null)
                            petManager.DismissPet(-1);
                    }
                }
            }
        }

        //Override starts exit timer (so we cant exit)
        //checks if carrying player corpse
        public override void SetPosition(MapItem mapItem)
        {
            base.SetPosition(mapItem); 

            ExitSeconds = 30;

            //TODO: Disposed error here
            Timer_Exit.Stop();
            Timer_Exit.Start();

            Timer_HexDamage_Stop();

            if (mapItem.TerrainType == "Water" || mapItem.TerrainType == "Door" || mapItem.TerrainType == "SDoor")
            {
                if (mapItem.ColorUrl.IndexOf("Lava2") > -1)
                    Timer_HexDamage_Start("Lava2");
                else if (mapItem.ColorUrl.IndexOf("Lava") > -1)
                    Timer_HexDamage_Start("Lava");
                else if (mapItem.TerrainType == "Water")
                    Timer_HexDamage_Start("Water");
            }

            //If we're holding another characters corpse, pass the new position to the characters corpse
            //the corpse will move the character accordingly
            Loot leftHandItem = this.LeftHand;
            if (leftHandItem != null)
            {
                if (leftHandItem is CorpseCharacter)
                {
                    CorpseCharacter corpse = (CorpseCharacter)leftHandItem;
                    corpse.MoveGhost(mapItem);
                }
            }
            Loot rightHandItem = this.RightHand;
            if (rightHandItem != null)
            {
                if (rightHandItem is CorpseCharacter)
                {
                    CorpseCharacter corpse = (CorpseCharacter)this.RightHand;
                    corpse.MoveGhost(mapItem);
                }
            }

            TradeData tData = tradeData;
            if (tData != null) 
                tData.CancelTrade(this, false);

            cancelAllPendingInput();
        }

        

        //Overrides to modify stats (Creatures stats are not effected by weapons)
        public override Loot LeftHand
        {
            set
            {
                //Only remove stats if we're sure we are replacing the item with null
                if (value == null && base.LeftHand != null && base.LeftHand is Equipment)
                {
                    Equipment lefthand = (Equipment)base.LeftHand;
                    if ((lefthand.Slot == "EitherHand" || lefthand.Slot == "LeftHand") && equipManager.MeetsRequirements(lefthand))
                    {
                        Armor = Armor - lefthand.Armor;
                        AgilityAdd = AgilityAdd - lefthand.Agility;
                        DexterityAdd = DexterityAdd - lefthand.Dexterity;
                        IntelligenceAdd = IntelligenceAdd - lefthand.Intelligence;
                        StrengthAdd = StrengthAdd - lefthand.Strength;
                        WisdomAdd = WisdomAdd - lefthand.Wisdom;

                        HPRegen = HPRegen - lefthand.HP_Regen;
                        MaxHPAdd = MaxHPAdd - lefthand.HP;
                        if (HP > MaxHP)
                            HP = MaxHP;

                        StaminaRegen = StaminaRegen - lefthand.Stam_Regen;
                        MaxStaminaAdd = MaxStaminaAdd - lefthand.Stam;
                        if (Stamina > MaxStamina)
                            Stamina = MaxStamina;

                        ManaRegen = ManaRegen - lefthand.Mana_Regen;
                        MaxManaAdd = MaxManaAdd - lefthand.Mana;
                        if (Mana > MaxMana)
                            Mana = MaxMana;

                        ResistFire = ResistFire - lefthand.ResistFire;
                        ResistIce = ResistIce - lefthand.ResistIce;
                        ResistHoly = ResistHoly - lefthand.ResistHoly;
                        ResistUnholy = ResistUnholy - lefthand.ResistUnholy;
                        ResistMagic = ResistMagic - lefthand.ResistMagic;
                        ResistPhysical = ResistPhysical - lefthand.ResistPhysical;
                    }
                }
                //Allways add stats if value is equipment (sometimes we need to re-apply stats if we suddenly meet requirements such as when we level)
                if (value is Equipment)
                {
                    Equipment lefthand = (Equipment)value;
                    if ((lefthand.Slot == "EitherHand" || lefthand.Slot == "LeftHand") && equipManager.MeetsRequirements(lefthand))
                    {
                        Armor = Armor + lefthand.Armor;
                        AgilityAdd = AgilityAdd + lefthand.Agility;
                        DexterityAdd = DexterityAdd + lefthand.Dexterity;
                        IntelligenceAdd = IntelligenceAdd + lefthand.Intelligence;
                        StrengthAdd = StrengthAdd + lefthand.Strength;
                        WisdomAdd = WisdomAdd + lefthand.Wisdom;

                        HPRegen = HPRegen + lefthand.HP_Regen;
                        MaxHPAdd = MaxHPAdd + lefthand.HP;
                        StaminaRegen = StaminaRegen + lefthand.Stam_Regen;
                        MaxStaminaAdd = MaxStaminaAdd + lefthand.Stam;
                        ManaRegen = ManaRegen + lefthand.Mana_Regen;
                        MaxManaAdd = MaxManaAdd + lefthand.Mana;

                        ResistFire = ResistFire + lefthand.ResistFire;
                        ResistIce = ResistIce + lefthand.ResistIce;
                        ResistHoly = ResistHoly + lefthand.ResistHoly;
                        ResistUnholy = ResistUnholy + lefthand.ResistUnholy;
                        ResistMagic = ResistMagic + lefthand.ResistMagic;
                        ResistPhysical = ResistPhysical + lefthand.ResistPhysical;
                    }
                }
                //We dont need to re-check the right hand unless the left hand actually got added or removed
                if (value != null && base.LeftHand == null && (base.RightHand != null && base.RightHand is Equipment))
                {
                    Equipment righthand = (Equipment)base.RightHand;
                    if (righthand.Slot == "2Hand" && equipManager.MeetsRequirements(righthand))
                    {
                        RightHand = null;
                        _RightHand = righthand;
                    }
                }
                if (value == null && base.LeftHand != null && (base.RightHand != null && base.RightHand is Equipment))
                {
                    Equipment righthand = (Equipment)base.RightHand;
                    if (righthand.Slot == "2Hand" && equipManager.MeetsRequirements(righthand))
                    {
                        base.LeftHand = value;
                        RightHand = _RightHand;
                        return;
                    }
                }
                base.LeftHand = value;
            }
            get
            {
                return _LeftHand;
            }
        }
        public override Loot RightHand
        {
            set
            {
                if (base.RightHand != null && base.RightHand is Equipment && value == null)
                {
                    Equipment righthand = (Equipment)base.RightHand;
                    if ((righthand.Slot == "EitherHand" || righthand.Slot == "RightHand" || (righthand.Slot == "2Hand" && LeftHand == null)) && equipManager.MeetsRequirements(righthand))
                    {
                        Armor = Armor - righthand.Armor;
                        AgilityAdd = AgilityAdd - righthand.Agility;
                        DexterityAdd = DexterityAdd - righthand.Dexterity;
                        IntelligenceAdd = IntelligenceAdd - righthand.Intelligence;
                        StrengthAdd = StrengthAdd - righthand.Strength;
                        WisdomAdd = WisdomAdd - righthand.Wisdom;

                        HPRegen = HPRegen - righthand.HP_Regen;
                        MaxHPAdd = MaxHPAdd - righthand.HP;
                        if (HP > MaxHP)
                            HP = MaxHP;

                        StaminaRegen = StaminaRegen - righthand.Stam_Regen;
                        MaxStaminaAdd = MaxStaminaAdd - righthand.Stam;
                        if (Stamina > MaxStamina)
                            Stamina = MaxStamina;

                        ManaRegen = ManaRegen - righthand.Mana_Regen;
                        MaxManaAdd = MaxManaAdd - righthand.Mana;
                        if (Mana > MaxMana)
                            Mana = MaxMana;

                        ResistFire = ResistFire - righthand.ResistFire;
                        ResistIce = ResistIce - righthand.ResistIce;
                        ResistHoly = ResistHoly - righthand.ResistHoly;
                        ResistUnholy = ResistUnholy - righthand.ResistUnholy;
                        ResistMagic = ResistMagic - righthand.ResistMagic;
                        ResistPhysical = ResistPhysical - righthand.ResistPhysical;
                    }
                }
                if (value != null && value is Equipment)
                {
                    Equipment righthand = (Equipment)value;
                    if ((righthand.Slot == "EitherHand" || righthand.Slot == "RightHand" || (righthand.Slot == "2Hand" && LeftHand == null)) &&  equipManager.MeetsRequirements(righthand))
                    {
                        Armor = Armor + righthand.Armor;
                        AgilityAdd = AgilityAdd + righthand.Agility;
                        DexterityAdd = DexterityAdd + righthand.Dexterity;
                        IntelligenceAdd = IntelligenceAdd + righthand.Intelligence;
                        StrengthAdd = StrengthAdd + righthand.Strength;
                        WisdomAdd = WisdomAdd + righthand.Wisdom;

                        HPRegen = HPRegen + righthand.HP_Regen;
                        MaxHPAdd = MaxHPAdd + righthand.HP;
                        StaminaRegen = StaminaRegen + righthand.Stam_Regen;
                        MaxStaminaAdd = MaxStaminaAdd + righthand.Stam;
                        ManaRegen = ManaRegen + righthand.Mana_Regen;
                        MaxManaAdd = MaxManaAdd + righthand.Mana;

                        ResistFire = ResistFire + righthand.ResistFire;
                        ResistIce = ResistIce + righthand.ResistIce;
                        ResistHoly = ResistHoly + righthand.ResistHoly;
                        ResistUnholy = ResistUnholy + righthand.ResistUnholy;
                        ResistMagic = ResistMagic + righthand.ResistMagic;
                        ResistPhysical = ResistPhysical + righthand.ResistPhysical;
                    }
                }
                base.RightHand = value;
            }
            get
            {
                return _RightHand;
            }
        }

        public override bool grantExpTo(Character character)
        {
            return base.grantExpTo(character);
        }

        public void UpdateEquipment()
        {
            try
            {
                ClientSocket.socket.BeginSend(equipManager.toXML(this));
            }
            catch { }
        }

        override public void PlaySound(string Name, int MapX, int MapY)
        {
            try
            {
                string result = "";

                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                xmldoc.WriteStartElement("playsound");
                xmldoc.WriteAttributeString("name", Name.ToString());
                xmldoc.WriteAttributeString("mapx", MapX.ToString());
                xmldoc.WriteAttributeString("mapy", MapY.ToString());
                xmldoc.WriteEndElement();
                xmldoc.Flush();
                xmldoc.Close();
                stringWriter.Flush();
                result = stringWriter.ToString();

                ClientSocket.socket.BeginSend(result);
            }
            catch { }
        }

        private long busyId = 0;
        private object busyLock = new object();
        public long getBusyId()
        {
            lock (busyLock)
            {
                return busyId;
            }
        }

        //Adds or removes a busy counter from client
        public void SetBusy(bool value)
        {
            try
            {
                string result = "";

                lock (busyLock)
                {
                    busyId++;

                    StringWriter stringWriter = new StringWriter();
                    XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                    xmldoc.WriteStartElement("setbusy");
                    xmldoc.WriteAttributeString("busyid", busyId.ToString());
                    xmldoc.WriteAttributeString("value", value.ToString());
                    xmldoc.WriteEndElement();
                    xmldoc.Flush();
                    xmldoc.Close();
                    stringWriter.Flush();
                    result = stringWriter.ToString();
                }

                ClientSocket.socket.BeginSend(result);
            }
            catch (Exception ex) 
            {
                if (ClientSocket.socket.Connected)
                    SetBusy(value);
            }
        }


        public void AddSpellPages(SpellPage SpellPage)
        {
            List<SpellPage> temp = new List<SpellPage>();
            temp.Add(SpellPage);
            AddSpellPages(temp);
        }
        //Send Spells to client
        public void AddSpellPages(List<SpellPage> SpellPages)
        {
            try
            {
                string result = "";
                XmlDocument xmlDoc = new XmlDocument();
                XmlNode RootNode = xmlDoc.CreateElement("spellpages");
                RootNode.InnerXml = "";
                string innerXml = "";
                foreach (SpellPage spellPage in SpellPages)
                {
                    innerXml = innerXml + spellPage.toXML();
                }
                RootNode.InnerXml = innerXml;

                xmlDoc.AppendChild(RootNode);

                result = xmlDoc.InnerXml.ToString();

                ClientSocket.socket.BeginSend(result);
            }
            catch { }
        }

        //Adds a message to be sent to client
        public void AddMessage(Message msg)
        {
            try
            {
                ClientSocket.socket.BeginSend(msg.toXML());
            }
            catch { }
        }

        //Adds creatureBases to list to be sent to client
        public void AddCreatureBase(CreatureBase creatureBase)
        {
            try
            {
                ClientSocket.socket.BeginSend(creatureBase.toXML(this));
            }
            catch { }
        }

        //Updates creatureBases Stamina
        public void UpdateCreatureBaseStamina(CreatureBase creatureBase)
        {
            if (creatureBase.Faction != Faction)
                return;

            try
            {
                ClientSocket.socket.BeginSend("<updateCbStam guid=\"" + creatureBase.CreatureID.ToString() + "\" stam=\"" + creatureBase.Stamina.ToString() + "\" maxStam=\"" + creatureBase.MaxStamina.ToString() + "\" />");
            }
            catch { }
        }

        public void UpdateCreatureBaseHp(CreatureBase creatureBase)
        {
            try
            {
                ClientSocket.socket.BeginSend("<updateCbHp guid=\"" + creatureBase.CreatureID.ToString() + "\" hp=\"" + creatureBase.HP.ToString() + "\" maxHp=\"" + creatureBase.MaxHP.ToString() + "\" />");
            }
            catch { }
        }

        //Updates creatureBases Mana
        public void UpdateCreatureBaseMana(CreatureBase creatureBase)
        {
            if (creatureBase.Faction != Faction)
                return;

            try
            {
                ClientSocket.socket.BeginSend("<updateCbMana guid=\"" + creatureBase.CreatureID.ToString() + "\" mana=\"" + creatureBase.Mana.ToString() + "\" maxMana=\"" + creatureBase.MaxMana.ToString() + "\" />");
            }
            catch { }
        }

        private decimal currentWeight = -1;
        public decimal getWeight()
        {
            return currentWeight;
        }
        public int getMaxWeight()
        {
            return 30 + StrengthTotal;
        }
        public decimal get0verweightBy()
        {
            if (getWeight() > getMaxWeight())
                return getWeight() - getMaxWeight();

            return 0;
        }

        public void updateWeight()
        {
            decimal calculatedWeight = 0;
            calculatedWeight += equipManager.totalWeight();
            calculatedWeight += bagManager.totalWeight();
            calculatedWeight += beltManager.totalWeight();

            calculatedWeight += System.Convert.ToDecimal(Math.Floor(Coins / 100.0) / 10);

            Loot leftHand = LeftHand;
            if (leftHand != null)
                calculatedWeight += leftHand.Weight;

            Loot rightHand = RightHand;
            if (rightHand != null)
                calculatedWeight += rightHand.Weight;

            if (calculatedWeight != currentWeight)
            {
                currentWeight = calculatedWeight;

                try
                {
                    ClientSocket.socket.BeginSend("<weight value=\"" + currentWeight.ToString() + "\" />");
                }
                catch { }
            }
        }


        private long updateSequence = 0;
        private object updateCharLock = new object();
        public override void Update_Character()
        {
            try
            {
                string result = "";
                lock (updateCharLock)
                {
                    updateSequence++;
                    result = "<mycharacter seq=\"" + updateSequence.ToString() + "\" >" + this.toXMLCharacter(this) + "</mycharacter>";
                }

                ClientSocket.socket.BeginSend(result);
            }
            catch { }
        }

        public void AddAnimation(string name, int mapid, int mapx, int mapy, int layer)
        {
            ClientSocket.socket.BeginSend("<fieldanimation name=\"" + name + "\" mapid=\"" + mapid + "\" mapx=\"" + mapx + "\" mapy=\"" + mapy + "\" layer=\"" + layer + "\" />");
        }


        private List<string> knownCharImages = new List<string>();
        private List<string> knownFieldImages = new List<string>();
        //Currently only used due to creatures left / right hands. Ground loot is always sent as it is always within visible range.
        private List<string> knownLootImages = new List<string>();

        public void AddMapItem(MapItem mapitem)
        {
            List<MapItem> mapitems = new List<MapItem>();
            mapitems.Add(mapitem);
            AddMapItems(mapitems, false);
        }
        public void AddMapItems(List<MapItem> mapitems, bool Refresh)
        {
            //int x = 0;
            //while (x < 100)
            //{
                //x++;
                try
                {
                    string result = "";

                    string innerXml = "";
                    string characterImagesXml = "";
                    string fieldImagesXml = "";
                    string lootImagesXml = "";

                    foreach (MapItem mapitem in mapitems)
                    {
                        //If the mapitem is within range of the screen, just send the mapitem
                        if (Math.Abs(mapitem.MapX - MapX) <= 4 && Math.Abs(mapitem.MapY - MapY) <= 4)
                        {
                            innerXml = innerXml + mapitem.toXML(this);
                        }
                        //Extract images new to the client for items out of range.
                        else
                        {
                            
                            if (knownFieldImages.Contains(mapitem.ColorUrl) == false)
                            {
                                knownFieldImages.Add(mapitem.ColorUrl);
                                fieldImagesXml = fieldImagesXml + "<i v=\"" + mapitem.ColorUrl + "\"/>";
                            }
                            if (mapitem.TerrainUrl != "" && knownFieldImages.Contains(mapitem.TerrainUrl) == false)
                            {
                                knownFieldImages.Add(mapitem.TerrainUrl);
                                fieldImagesXml = fieldImagesXml + "<i v=\"" + mapitem.TerrainUrl + "\"/>";
                            }
                            if (mapitem.Terrain2 != "" && knownFieldImages.Contains(mapitem.Terrain2) == false)
                            {
                                knownFieldImages.Add(mapitem.Terrain2);
                                fieldImagesXml = fieldImagesXml + "<i v=\"" + mapitem.Terrain2 + "\"/>";
                            }
                            if (mapitem.TerrainOver != "" && knownFieldImages.Contains(mapitem.TerrainOver) == false)
                            {
                                knownFieldImages.Add(mapitem.TerrainOver);
                                fieldImagesXml = fieldImagesXml + "<i v=\"" + mapitem.TerrainOver + "\"/>";
                            }
                            if (mapitem.SpellLayer2 != null &&
                                mapitem.SpellLayer2.spellIcon != null &&
                                mapitem.SpellLayer2.spellIcon.FieldImageURL != "" &&
                                knownFieldImages.Contains(mapitem.SpellLayer2.spellIcon.FieldImageURL) == false)
                            {
                                knownFieldImages.Add(mapitem.SpellLayer2.spellIcon.FieldImageURL);
                                fieldImagesXml = fieldImagesXml + "<i v=\"" + mapitem.SpellLayer2.spellIcon.FieldImageURL + "\"/>";
                            }
                            foreach (Spell spell in mapitem.SpellLayer0)
                            {
                                if (spell.spellIcon.FieldImageURL != "" &&
                                    fieldImagesXml.Contains(spell.spellIcon.FieldImageURL) == false)
                                {
                                    knownFieldImages.Add(spell.spellIcon.FieldImageURL);
                                    fieldImagesXml = fieldImagesXml + "<i v=\"" + spell.spellIcon.FieldImageURL + "\"/>";
                                }
                            }
                            foreach (Spell spell in mapitem.SpellLayer1)
                            {
                                if (spell.spellIcon.FieldImageURL != "" &&
                                    fieldImagesXml.Contains(spell.spellIcon.FieldImageURL) == false)
                                {
                                    knownFieldImages.Add(spell.spellIcon.FieldImageURL);
                                    fieldImagesXml = fieldImagesXml + "<i v=\"" + spell.spellIcon.FieldImageURL + "\"/>";
                                }
                            }
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (knownCharImages.Contains(creatureBase.ImageURL) == false)
                                {
                                    knownCharImages.Add(creatureBase.ImageURL);
                                    characterImagesXml = characterImagesXml + "<i v=\"" + creatureBase.ImageURL + "\"/>";
                                }
                                if (creatureBase.LeftHand != null && knownLootImages.Contains(creatureBase.LeftHand.ImageURL) == false)
                                {
                                    knownLootImages.Add(creatureBase.LeftHand.ImageURL);
                                    lootImagesXml = lootImagesXml + "<i v=\"" + creatureBase.LeftHand.ImageURL + "\"/>"; 
                                }
                                if (creatureBase.RightHand != null && knownLootImages.Contains(creatureBase.RightHand.ImageURL) == false)
                                {
                                    knownLootImages.Add(creatureBase.RightHand.ImageURL);
                                    lootImagesXml = lootImagesXml + "<i v=\"" + creatureBase.RightHand.ImageURL + "\"/>"; 
                                }
                            }
                        }
                    }

                    if (innerXml == "" && fieldImagesXml == "" && characterImagesXml == "" && lootImagesXml == "")
                        return;

                    StringWriter stringWriter = new StringWriter();
                    XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                    xmldoc.WriteStartElement("fieldupdate");
                    xmldoc.WriteAttributeString("r", Refresh.ToString());

                    xmldoc.WriteStartElement("mitems");
                    if (innerXml != "") xmldoc.WriteRaw(innerXml);
                    xmldoc.WriteEndElement();

                    xmldoc.WriteStartElement("fitems");
                    if (fieldImagesXml != "") xmldoc.WriteRaw(fieldImagesXml);
                    xmldoc.WriteEndElement();

                    xmldoc.WriteStartElement("citems");
                    if (characterImagesXml != "") xmldoc.WriteRaw(characterImagesXml);
                    xmldoc.WriteEndElement();

                    xmldoc.WriteStartElement("litems");
                    if (lootImagesXml != "") xmldoc.WriteRaw(lootImagesXml);
                    xmldoc.WriteEndElement();


                    xmldoc.WriteEndElement();
                    xmldoc.Flush();

                    xmldoc.Close();

                    stringWriter.Flush();

                    result = stringWriter.ToString();

                    ClientSocket.socket.BeginSend(result);
                }
                catch (Exception ex)
                {
                    string message = ex.Message;
                }
            //}
        }
        
        //Adds LootItems to list to send to client
        public void AddFieldLoot(FieldLootItems fieldLootItem)
        {
            List<FieldLootItems> fieldloot = new List<FieldLootItems>();
            fieldloot.Add(fieldLootItem);
            AddFieldLoot(fieldloot,false);
        }
        public void AddFieldLoot(List<FieldLootItems> fieldLootItems, bool Refresh)
        {
            try
            {
                string result = "";

                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                xmldoc.WriteStartElement("fieldlootupdate");
                xmldoc.WriteAttributeString("refresh", Refresh.ToString());

                string innerXml = "";
                foreach (FieldLootItems fieldloot in fieldLootItems)
                {
                    innerXml = innerXml + fieldloot.toXML(this);
                }
                if (innerXml != "") xmldoc.WriteRaw(innerXml);

                xmldoc.WriteEndElement();
                xmldoc.Flush();

                xmldoc.Close();

                stringWriter.Flush();

                result = stringWriter.ToString();

                ClientSocket.socket.BeginSend(result);
            }
            catch { }
        }

        override protected void Timer_HexDamage_Elapsed(object source, ElapsedEventArgs e)
        {
            LockItem myLockItem = GameHandler.GetLockItem(MapID, Instance);
            lock (myLockItem.LockObj)
            {
                //CHECK IF WE'RE IN A VALID STATE TO CONTINUE EXECUTION/////////////////////////

                //System.Reflection.MethodBase currentMethodBase = System.Reflection.MethodBase.GetCurrentMethod();
                //Delegate currentMethodDelegate = Delegate.CreateDelegate(currentMethodBase.GetType(), this, currentMethodBase.Name);

                //Create a delegate for this method incase it cant be run right now
                Action<object, ElapsedEventArgs> thisMethod = (Action<object, ElapsedEventArgs>)Timer_HexDamage_Elapsed;
                //Record this method's arguments
                Object[] thisMethodArgs = { source, e };
                //Pass the delegate and args when we check if we're mid map transfer. If yes, they will be recorded and run again automatically.
                if (isChangingMaps(thisMethod, thisMethodArgs) == true)
                    return;

                //A map transfer happened, but its already complete. Immediately re-run this method on a different thread. 
                //We need to use a different thread because otherwise the current thread would lock 2 maps possibly resulting in a deadlock.
                if (MapID != myLockItem.MapID)
                {
                    thisMethod.BeginInvoke(MapID, e, null, null);
                    return;
                }
                //STATE IS VALID, CONTINUE EXECUTION///////////////////////////////////////////

                //Timer has been shut off, do nothing
                if (Timer_HexDamageCounter == -1)
                    return;

                //Increments the counter
                base.Timer_HexDamage_Elapsed(source, e);

                //We need to keep this timer running even if the character is dead
                //If they get raised in the water, the timer will pick up, only setPosition will stop this timer 
                if (this.HP < 1)
                {
                    //Just incase this timer ticks at the same time exit game is fired. timer may get disposed.
                    try
                    {
                        Timer_HexDamage.Start();
                        Timer_HexDamageCounter = 0;
                    }
                    catch { }

                    return;
                }

                Message msg;
                if (Timer_HexDamageType == "Water")
                {
                    if (buffManager.HasBreatheWater() == true)
                        Timer_HexDamageCounter = 0;

                    if (Timer_HexDamageCounter == 4)
                    {
                        msg = new Message();
                        msg.CreatureID = this.CreatureID;
                        msg.Type = "damage";
                        msg.Text = "You are sinking!";
                        AddMessage(msg);
                    }
                    else if (Timer_HexDamageCounter == 6)
                    {
                        msg = new Message();
                        msg.CreatureID = this.CreatureID;
                        msg.Type = "damage";
                        msg.Text = "You are submerged!";
                        AddMessage(msg);
                    }
                    else if (Timer_HexDamageCounter == 8)
                    {
                        msg = new Message();
                        msg.CreatureID = this.CreatureID;
                        msg.Type = "damage";
                        msg.Text = "You are nearly out of breath!";
                        AddMessage(msg);
                    }
                    else if (Timer_HexDamageCounter >= 10)
                    {
                        //Damage Character for drowning
                        this.HP = this.HP - 100;

                        List<Character> CharsToUpdate = new List<Character>();
                        
                        foreach (MapItem mapitem in currentMapItem.mapItemsWithin8)
                        {
                            if (System.Math.Abs(mapitem.MapX - this.MapX) <= 4 && System.Math.Abs(mapitem.MapY - this.MapY) <= 4)
                            {
                                foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                                {
                                    if (creaturebase is Character)
                                        CharsToUpdate.Add((Character)creaturebase);
                                }
                            }
                        }
                        this.Update_Character();
                        foreach (Character character in CharsToUpdate)
                        {
                            if (this.HP < 1)
                            {
                                character.AddMapItem(currentMapItem);
                                character.PlaySound(this.SoundDeath, this.MapX, this.MapY);
                            }
                            else
                                character.UpdateCreatureBaseHp(this);
                        }

                        if (this.HP < 1)
                        {
                            msg = new Message();
                            msg.CreatureID = this.CreatureID;
                            msg.Type = "damaged";
                            msg.Text = "You have drown!";
                            AddMessage(msg);

                            this.DropLoot(-1);
                            this.Timer_Respawn.Start();
                        }
                        else
                        {
                            msg = new Message();
                            msg.CreatureID = this.CreatureID;
                            msg.Type = "damaged";
                            msg.Text = "You are drowning!";
                            AddMessage(msg);
                        }
                    }
                }
                else if (Timer_HexDamageType == "Lava2")
                {
                    if (buffManager.HasBreatheWater() == true)
                        Timer_HexDamageCounter = 0;

                    //Damage Character for drowning
                    int lavaFireDamage = 450;
                    lavaFireDamage = CalculateGetSpellDamagePerResists(lavaFireDamage, "Fire");


                    msg = new Message();
                    msg.CreatureID = this.CreatureID;
                    msg.Type = "damaged";
                    msg.Text = "You are burning! (" + lavaFireDamage.ToString() + ")";
                    AddMessage(msg);

                    List<Character> CharsToUpdate = new List<Character>();

                    foreach (MapItem mapitem in currentMapItem.mapItemsWithin8)
                    {
                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                        {
                            if (creaturebase is Character)
                                CharsToUpdate.Add((Character)creaturebase);
                        }
                    }
                    InflictDamage(lavaFireDamage, -1);
                    this.Update_Character();
                    foreach (Character character in CharsToUpdate)
                    {
                        if (this.HP < 1)
                        {
                            character.AddMapItem(currentMapItem);
                            character.PlaySound(this.SoundDeath, this.MapX, this.MapY);
                        }
                        else
                            character.UpdateCreatureBaseHp(this);
                    }

                    if (this.HP < 1)
                    {
                        msg = new Message();
                        msg.CreatureID = this.CreatureID;
                        msg.Type = "damaged";
                        msg.Text = "You have burned to death!";
                        AddMessage(msg);
                    }
                }
                else if (Timer_HexDamageType == "Lava")
                {
                    if (buffManager.HasBreatheWater() == true)
                        Timer_HexDamageCounter = 0;

                    //Damage Character for drowning
                    int lavaFireDamage = 250;
                    lavaFireDamage = CalculateGetSpellDamagePerResists(lavaFireDamage, "Fire");

                    msg = new Message();
                    msg.CreatureID = this.CreatureID;
                    msg.Type = "damaged";
                    msg.Text = "You are burning! (" + lavaFireDamage.ToString() + ")";
                    AddMessage(msg);

                    List<Character> CharsToUpdate = new List<Character>();

                    foreach (MapItem mapitem in currentMapItem.mapItemsWithin8)
                    {
                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                        {
                            if (creaturebase is Character)
                                CharsToUpdate.Add((Character)creaturebase);
                        }
                    }
                    InflictDamage(lavaFireDamage, -1);
                    this.Update_Character();
                    foreach (Character character in CharsToUpdate)
                    {
                        if (this.HP < 1)
                        {
                            character.AddMapItem(currentMapItem);
                            character.PlaySound(this.SoundDeath, this.MapX, this.MapY);
                        }
                        else
                            character.UpdateCreatureBaseHp(this);
                    }

                    if (this.HP < 1)
                    {
                        msg = new Message();
                        msg.CreatureID = this.CreatureID;
                        msg.Type = "damaged";
                        msg.Text = "You have burned to death!";
                        AddMessage(msg);
                    }
                }

            }//End Lock

            Timer_HexDamage.Start();
        }

        private void Timer_Exit_Elapsed(object source, ElapsedEventArgs e)
        {
            if (ExitSeconds > 0)
            {
                ExitSeconds--;

                //Got object disposed error here?  No big deal, somehow the character exited while this timer was running which
                //shouldnt happen, but havnt figured out why so just putting a try / catch for now.
                try
                {
                    Timer_Exit.Start();
                }
                catch { }
            }
        }

        private void Timer_AutoSave_Elapsed(object source, ElapsedEventArgs e)
        {
            try
            {
                if (MapID != -1 && Instance != -1 && ClientSocket.succesfullyEntered)
                {
                    Timer_AutoSave.Start();
                    SaveCharacter();
                }
            }
            catch { }
        }

        private void SaveCharacter()
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_Update", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SQLCom.Parameters.AddWithValue("@ID", this.ID);

            SQLCom.Parameters.AddWithValue("@MapX", this.MapX);
            SQLCom.Parameters.AddWithValue("@MapY", this.MapY);

            SQLCom.Parameters.AddWithValue("@MaxHP", this.MaxHPBase);
            SQLCom.Parameters.AddWithValue("@HP", this.HP);
            SQLCom.Parameters.AddWithValue("@MaxStamina", this.MaxStaminaBase);
            SQLCom.Parameters.AddWithValue("@Stamina", this.Stamina);
            SQLCom.Parameters.AddWithValue("@MaxMana", this.MaxManaBase);
            SQLCom.Parameters.AddWithValue("@Mana", this.Mana);

            SQLCom.Parameters.AddWithValue("@Strength", this.Strength);
            SQLCom.Parameters.AddWithValue("@Dexterity", this.Dexterity);
            SQLCom.Parameters.AddWithValue("@Agility", this.Agility);
            SQLCom.Parameters.AddWithValue("@Wisdom", this.Wisdom);
            SQLCom.Parameters.AddWithValue("@Intelligence", this.Intelligence);

            SQLCom.Parameters.AddWithValue("@LastMapID", this.MapID);
            SQLCom.Parameters.AddWithValue("@LastInstance", this.Instance);

            SQLCom.Parameters.AddWithValue("@NumCoins", this.Coins);
            SQLCom.Parameters.AddWithValue("@BankCoins", this.bankManager.BankCoins);

            SQLCom.Parameters.AddWithValue("@ImageURL", this.ImageURL);
            SQLCom.Parameters.AddWithValue("@ShowTips", this.showTips);

            SQLCom.Parameters.AddWithValue("@BindMapID", this.BindMapID);
            SQLCom.Parameters.AddWithValue("@BindMapX", this.BindMapX);
            SQLCom.Parameters.AddWithValue("@BindMapY", this.BindMapY);

            Loot leftHand = this.LeftHand;
            if (leftHand != null && leftHand.ID > 0)
            {
                SQLCom.Parameters.AddWithValue("@LeftHand", leftHand.ID);
                SQLCom.Parameters.AddWithValue("@LeftHand_BoundTo", leftHand.BoundTo);
            }

            Loot rightHand = this.RightHand;
            if (rightHand != null && rightHand.ID > 0)
            {
                SQLCom.Parameters.AddWithValue("@RightHand", rightHand.ID);
                SQLCom.Parameters.AddWithValue("@RightHand_BoundTo", rightHand.BoundTo);
            }

            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();

            //SAVE BAG INFORMATION
            if (bagManager != null)
                bagManager.SaveBag();

            this.beltManager.SaveBelt();
            this.equipManager.SaveEquipment();
            this.bankManager.SaveBank();
            this.spellManager.SaveSpells();
            this.skillManager.SaveSkills();
            this.hateManager.saveSelfDefenseFlags();
            this.chatChannelManager.save();
            this.weaponSkillManager.saveSkills();
            this.buffManager.SaveBuffs();
            this.recipieManager.saveRecipies();
        }
        public void ExitGame(bool changeServer, string ExitSound)
        {
            ExitGame(changeServer, ExitSound, false);
        }
        public void ExitGame(bool changeServer, string ExitSound, bool CharacterRemovedFromField)
        {
            //If the character has already been removed, dont do anything.
            if (Managers.characterManager.tryRemoveCharacter(UserID) == false)
                return;



            List<Character> CharsToUpdate = new List<Character>();
            List<MapItem> MapItemsToUpdate = new List<MapItem>();

            if (this.HP < 1 && ClientSocket.succesfullyEntered == true)
                this.GameHandler.Resurrect(this);

            //Get Lock
            LockItem MyLock = GameHandler.GetLockItem(MapID, Instance);

            this.Timer_Regen.Stop();

            if (ClientSocket.succesfullyEntered)
                SaveCharacter();

            //LOCK MAP
            lock (MyLock.LockObj)
            {
                //CHECK IF WE'RE IN A VALID STATE TO CONTINUE EXECUTION/////////////////////////

                //System.Reflection.MethodBase currentMethodBase = System.Reflection.MethodBase.GetCurrentMethod();
                //Delegate currentMethodDelegate = Delegate.CreateDelegate(currentMethodBase.GetType(), this, currentMethodBase.Name);

                //Create a delegate for this method incase it cant be run right now
                Action<bool, string, bool> thisMethod = (Action<bool, string, bool>)ExitGame;
                //Record this method's arguments
                Object[] thisMethodArgs = { changeServer, ExitSound, CharacterRemovedFromField };
                //Pass the delegate and args when we check if we're mid map transfer. If yes, they will be recorded and run again automatically.
                if (this.isChangingMaps(thisMethod, thisMethodArgs) == true)
                    return;

                //A map transfer happened, but its already complete. Immediately re-run this method on a different thread. 
                //We need to use a different thread because otherwise the current thread would lock 2 maps possibly resulting in a deadlock.
                if (this.MapID != MyLock.MapID)
                {
                    thisMethod.BeginInvoke(changeServer, ExitSound, CharacterRemovedFromField, null, null);
                    return;
                }
                //STATE IS VALID, CONTINUE EXECUTION///////////////////////////////////////////

                //Get Map
                Map MyMap = GameHandler.GetMap(MapID, Instance);

                MyMap.removeCreatureToProcess(this);

                TradeData tData = tradeData;
                if (tData != null) tData.CancelTrade(this, false);

                cancelAllPendingInput();

                //Dismiss All pets
                if (petManager != null)
                    petManager.DismissPet(-1);

                if (CharacterRemovedFromField == false)
                {
                    List<Loot> CorpsesToDrop = new List<Loot>();
                    if (LeftHand is ICorpse)
                    {
                        if (LeftHand is CorpseCharacter)
                        {
                            CorpseCharacter cc = (CorpseCharacter)LeftHand;
                            cc.CarrierCharacter = null;
                        }

                        CorpsesToDrop.Add(LeftHand);
                        LeftHand = null;
                    }
                    if (RightHand is ICorpse)
                    {
                        if (RightHand is CorpseCharacter)
                        {
                            CorpseCharacter cc = (CorpseCharacter)RightHand;
                            cc.CarrierCharacter = null;
                        }

                        CorpsesToDrop.Add(RightHand);
                        RightHand = null;
                    }

                    if (CorpsesToDrop.Count > 0)
                        MyMap.LootMngr.DropItems(MapX, MapY, CorpsesToDrop, false);

                    foreach (MapItem mapitem in MyMap.MapItems)
                    {
                        //Remove Character
                        if (mapitem.MapX == this.MapX && mapitem.MapY == this.MapY)
                        {
                            mapitem.CreaturesBases.Remove(this);
                            MapItemsToUpdate.Add(mapitem);
                        }
                        //Get Characters To Update
                        if ((mapitem.MapX >= this.MapX - 4 && mapitem.MapX <= this.MapX + 4) && (mapitem.MapY >= this.MapY - 4 && mapitem.MapY <= this.MapY + 4))
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                {
                                    Character character = (Character)creatureBase;
                                    CharsToUpdate.Add(character);
                                }
                            }
                        }
                    }
                    //Send Out Updates
                    foreach (Character character in CharsToUpdate)
                    {
                        character.AddMapItems(MapItemsToUpdate, false);
                    }
                }

                this.Timer_AutoSave.Stop();
                this.Timer_AutoSave.Dispose();

                Timer_HexDamage_Stop();

                Timer_Drop.Stop();
                Timer_Exit.Stop();

                //Remove any buffs tied to me that are on other creatures.
                buffManager.cancelAllTiedBuffs();

                //Do this just to stop the timers.
                List<Buff> buffs = buffManager.Buffs;
                foreach (Buff buff in buffs)
                {
                    buff.RemoveSpell(false, false);
                }
                buffManager.UpdateBuffs();

            }//End Lock
           

            //Send out friends list update
            Instance = -1;
            MapID = -1;

            if (changeServer == false)
            {
                Managers.characterManager.sendFriendOffline(ID);

                //This only happens if character fails to load (usually me coming from dev with something weird)
                if (chatChannelManager != null)
                    chatChannelManager.sendLogoutNotifications();
            }
        }
        public void Timer_Drop_Elapsed(object source, ElapsedEventArgs e)
        {
            ExitGame(false, "");           
        }

        //Removes clients busy
        private void Timer_Round_Elapsed(object source, ElapsedEventArgs e)
        {
            lock (Timer_Round)
            {
                if (_Timer_Round_IsRunning == false)
                    return;

                this.SetBusy(false);
                _Timer_Round_IsRunning = false;
            }

            //Dispatch the round elapsed event
            if (RoundElapsed != null)
                RoundElapsed(this);
        }

        public bool tryStopRoundTimer()
        {
            lock (Timer_Round)
            {
                if (_Timer_Round_IsRunning == false)
                    return false;

                _Timer_Round_IsRunning = false;
                Timer_Round.Stop();
            }
            return true;
        }

        //Timer Event, Auto Res for characters
        private void Timer_Respawn_Elapsed(object source, ElapsedEventArgs e)
        {
            GameHandler.Resurrect(this);
        }

        public string toXMLCharacter(Character sendingToCharacter)
        {
            string result = "";

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            xmldoc.WriteStartElement("a");
            xmldoc.WriteAttributeString("a", ID.ToString());
            xmldoc.WriteAttributeString("b", UserID.ToString());
            xmldoc.WriteAttributeString("c", CreatureID.ToString());
            xmldoc.WriteAttributeString("d", Name.ToString());

            xmldoc.WriteAttributeString("e", ImageURL.ToString());

            xmldoc.WriteAttributeString("f", Faction.ToString());
            xmldoc.WriteAttributeString("g", Gender.ToString());
            xmldoc.WriteAttributeString("h", MapX.ToString());
            xmldoc.WriteAttributeString("i", MapY.ToString());
            xmldoc.WriteAttributeString("j", MaxHP.ToString());
            xmldoc.WriteAttributeString("k", HP.ToString());
            xmldoc.WriteAttributeString("l", MaxStamina.ToString());
            xmldoc.WriteAttributeString("m", Stamina.ToString());
            xmldoc.WriteAttributeString("n", MaxMana.ToString());
            xmldoc.WriteAttributeString("o", Mana.ToString());

            xmldoc.WriteAttributeString("p", Strength.ToString());
            xmldoc.WriteAttributeString("q", Dexterity.ToString());
            xmldoc.WriteAttributeString("r", Agility.ToString());
            xmldoc.WriteAttributeString("s", Intelligence.ToString());
            xmldoc.WriteAttributeString("t", Wisdom.ToString());

            int valueToSend = StrengthAdd;
            if (valueToSend < Strength * -1)
                valueToSend = Strength * -1;
            xmldoc.WriteAttributeString("u", valueToSend.ToString());

            valueToSend = DexterityAdd;
            if (valueToSend < Dexterity * -1)
                valueToSend = Dexterity * -1;
            xmldoc.WriteAttributeString("v", valueToSend.ToString());

            valueToSend = AgilityAdd;
            if (valueToSend < Agility * -1)
                valueToSend = Agility * -1;
            xmldoc.WriteAttributeString("w", valueToSend.ToString());

            valueToSend = IntelligenceAdd;
            if (valueToSend < Intelligence * -1)
                valueToSend = Intelligence * -1;
            xmldoc.WriteAttributeString("x", valueToSend.ToString());

            valueToSend = WisdomAdd;
            if (valueToSend < Wisdom * -1)
                valueToSend = Wisdom * -1;
            xmldoc.WriteAttributeString("y", valueToSend.ToString());

            xmldoc.WriteAttributeString("z", ArmorTotal.ToString());

            xmldoc.WriteAttributeString("A", getResist("Fire").ToString());
            xmldoc.WriteAttributeString("B", getResist("Ice").ToString());
            xmldoc.WriteAttributeString("C", getResist("Holy").ToString());
            xmldoc.WriteAttributeString("D", getResist("Unholy").ToString());
            xmldoc.WriteAttributeString("E", getResist("Magic").ToString());
            xmldoc.WriteAttributeString("L", getResist("Physical").ToString());

            xmldoc.WriteAttributeString("F", MapID.ToString());
            xmldoc.WriteAttributeString("G", Instance.ToString());
            xmldoc.WriteAttributeString("H", Coins.ToString());

            xmldoc.WriteStartElement("I");
            if (LeftHand != null)
                xmldoc.WriteRaw(LeftHand.toXML(sendingToCharacter));
            xmldoc.WriteEndElement();

            xmldoc.WriteStartElement("J");
            if (RightHand != null)
                xmldoc.WriteRaw(RightHand.toXML(sendingToCharacter));
            xmldoc.WriteEndElement();

            xmldoc.WriteStartElement("K");
            if (WarmSpell != null)
                xmldoc.WriteRaw(WarmSpell.toXML());
            xmldoc.WriteEndElement();

            xmldoc.WriteEndElement();
            xmldoc.Flush();

            xmldoc.Close();

            stringWriter.Flush();

            result = stringWriter.ToString();

            return result;
        }

        //This will be passed to an async thread, do not call it directly. Only does the DB insert. 
        //They will refresh from the DB to get the new expire dates and adjust the debuff.
        private void SendKarma(int toCharacterId)
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_KarmaFlags_Insert", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SQLCom.Parameters.AddWithValue("@CharacterID", toCharacterId);
            SQLCom.Parameters.AddWithValue("@KarmaFromCharacterID", this.ID);

            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();
        }
        //These may be called as the result of send karma, which will update the current character
        private void SendKarmaAsyncResultLocal(IAsyncResult asyncResult)
        {
            try
            {
                Character character = (Character)asyncResult.AsyncState;
                character.UpdateKarma(true);
            }
            catch (Exception ex)
            {

            }
        }
        private void SendKarmaAsyncResultBroadcast(IAsyncResult asyncResult)
        {
            try
            {
                int characterIdToUpdate = (int)asyncResult.AsyncState;
                Managers.BeginSendToPrimary("<karmanotification characterid=\"" + characterIdToUpdate.ToString() + "\" />");
            }
            catch (Exception ex)
            {

            }
        }

        public void RemoveKarmaFrom(int characterId)
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_KarmaFlags_Delete", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SQLCom.Parameters.AddWithValue("@CharacterID", this.ID);
            SQLCom.Parameters.AddWithValue("@KarmaFromCharacterID", characterId);

            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();
        }


        

        public string getMailBox(bool sendToClient)
        {
            List<MailItem> mailItems = new List<MailItem>();

            //Load Mail Items
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_Mail_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", ID);
            MyCon.Open();

            SqlDataReader SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                MailItem mailItem = new MailItem(
                    int.Parse(SDR["ID"].ToString()),
                    int.Parse(SDR["FromCharacterID"].ToString()),
                    SDR["FromCharacterName"].ToString(),
                    SDR["Subject"].ToString(),
                    SDR["Message"].ToString(),
                    int.Parse(SDR["Coins"].ToString()),
                    int.Parse(SDR["Expires"].ToString()));

                mailItems.Add(mailItem);
            }
            SDR.Close();

            SQLCom.Parameters.Clear();
            SQLCom.CommandText = "Characters_Mail_Attachments_Select";
            SQLCom.Parameters.Add("@MailID", System.Data.SqlDbType.Int);
            foreach (MailItem mailItem in mailItems)
            {
                SQLCom.Parameters["@MailID"].Value = mailItem.ID;
                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    mailItem.addAttachment(
                        Managers.GameHandler.CreateItem(
                            int.Parse(SDR["ItemID"].ToString()),
                            int.Parse(SDR["ItemBoundTo"].ToString()),
                            true)
                        );
                }
                SDR.Close();
            }

            MyCon.Close();
            MyCon.Dispose();

            MailBoxData mailBoxData = new MailBoxData();
            mailBoxData.mailBoxItems = mailItems;

            List<Loot> myItems = new List<Loot>();

            if (LeftHand != null)
                myItems.Add(LeftHand);
            if (RightHand != null)
                myItems.Add(RightHand);

            List<Loot> characterBag = bagManager.getAllBagItems();
            foreach (Loot loot in characterBag)
                myItems.Add(loot);
    
            Loot[] characterBelt = beltManager.getBeltLootCopy();
            foreach (Loot loot in characterBelt)
            {
                if (loot != null)
                    myItems.Add(loot);
            }

            mailBoxData.myItems = myItems;

            string mailBoxXml = mailBoxData.toXML(this);

            if (sendToClient)
            {
                try
                {
                    ClientSocket.socket.BeginSend(mailBoxXml);
                }
                catch { }
            }
            
            return mailBoxXml;
        }

        public void UpdateKarma(bool sendMessage)
        {
            int currentKarma = hateManager.getKarmaCount();

            //Load karma flags
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_KarmaFlags_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", ID);
            MyCon.Open();

            SqlDataReader SDR = SQLCom.ExecuteReader();
            hateManager.clearKarmaFlags();
            while (SDR.Read())
            {
                hateManager.AddKarmaFlag(
                    int.Parse(SDR["KarmaFromCharacterID"].ToString()),
                    SDR["Name"] == DBNull.Value ? "Deleted Character" : SDR["Name"].ToString(),
                    int.Parse(SDR["MinutesRemaining"].ToString()));
            }
            SDR.Close();
            MyCon.Close();
            MyCon.Dispose();

            if (currentKarma != hateManager.getKarmaCount())
            {
                updateKarmaBuff();
                if (sendMessage)
                    SendMessage("You now have " + hateManager.getKarmaCount().ToString() + " point(s) of Karma!", "server");
            }
        }
        public void updateKarmaBuff()
        {
            Buff badKarmaBuff = buffManager.GetBuffByStackType("BadKarma");
            SpellIcon badKarmaIcon = null;
            CreatureBase thisCb = (CreatureBase)this;
            if (badKarmaBuff != null)
            {
                badKarmaBuff.RemoveSpell(false, false);

                if (hateManager.getKarmaCount() > 0)
                {
                    badKarmaIcon = badKarmaBuff.spellIcon;
                    badKarmaBuff = new Spell_BadKarma();
                    badKarmaBuff.Resume(thisCb, badKarmaIcon, -1, -1, -1, -1, -1, -1, null);
                }
            }
            else if (hateManager.getKarmaCount() > 0)
            {
                foreach (KeyValuePair<int, SpellIcon> keyValue in Managers.GameHandler.Spells)
                {
                    if (keyValue.Value.StackType == "BadKarma")
                    {
                        badKarmaIcon = keyValue.Value;
                    }
                }
                badKarmaBuff = new Spell_BadKarma();
                badKarmaBuff.Resume(thisCb, badKarmaIcon, -1, -1, -1, -1, -1, -1, null);
            }

            buffManager.UpdateBuffs();
        }

        public override void DropLoot(int SlayingCharID)
        {
            base.DropLoot(SlayingCharID);

            Character slayingCharacter = Managers.characterManager.getCharacter(SlayingCharID);

            //I have hate on this character, penalize them for killing me
            if (hateManager.GetCharacterHateInfo(SlayingCharID) != null)
            {
                //Async a thread to update their karma in the DB, 
                //We use the DB because it tracks and updates the expire times while offline. 
                //Also if the person is offline we would need to do an insert anyway.
                
                //When this thread completes, we either 1, notify the character to update karma if they're on this server
                //Or 2, send a broadcast to the primary to broadcast the update incase they are on a different server.

                //Character is on this server
                if (slayingCharacter != null)
                {
                    Action<int> sendKarma = (Action<int>)SendKarma;
                    sendKarma.BeginInvoke(SlayingCharID, (AsyncCallback)SendKarmaAsyncResultLocal, slayingCharacter);
                }
                //Server broadcast
                else
                {
                    Action<int> sendKarma = (Action<int>)SendKarma;
                    sendKarma.BeginInvoke(SlayingCharID, (AsyncCallback)SendKarmaAsyncResultBroadcast, SlayingCharID);
                }
            }
            //Attempt to remove their SD Flag
            else if (slayingCharacter != null)
                slayingCharacter.hateManager.ClearHateInfo(ID);

            Character myCharacter = this;
            CorpseCharacter myCorpse = new CorpseCharacter(GameHandler, myCharacter);
            myCorpse.Name = this.Name + "'s corpse";
            myCorpse.ID = -2;

            CharacterColorOverride cco = getColorOverride(currentColor);
            if (cco != null && cco.corpseImageName != null)
                myCorpse.ImageURL = cco.corpseImageName;
            else
                myCorpse.ImageURL = this.CorpseImageURL;

            myCorpse.ItemType = "Corpse";
            myCorpse.GameUID = this.GameHandler.ItemIDGen.GetUID();

            this.myCorpse = myCorpse;

            List<Loot> ItemsToDrop = new List<Loot>();
            ItemsToDrop.Add(myCorpse);

            bool updateCharacter = false;
            if (this.LeftHand != null)
            {
                //TODO: This should be done inside loot manager (Several other instances need to be moved also)
                if (this.LeftHand is CorpseCharacter)
                {
                    CorpseCharacter cc = (CorpseCharacter)this.LeftHand;
                    cc.CarrierCharacter = null;
                }

                ItemsToDrop.Add(this.LeftHand);
                this.LeftHand = null;
                updateCharacter = true;
            }
            if (this.RightHand != null)
            {
                //TODO: This should be done inside loot manager (Several other instances need to be moved also)
                if (this.RightHand is CorpseCharacter)
                {
                    CorpseCharacter cc = (CorpseCharacter)this.RightHand;
                    cc.CarrierCharacter = null;
                }

                ItemsToDrop.Add(this.RightHand);
                this.RightHand = null;
                updateCharacter = true;
            }
            if (updateCharacter == true)
                this.Update_Character();

            GameHandler.GetMap(MapID,Instance).LootMngr.DropItems(this.MapX, this.MapY, ItemsToDrop, true);
        }

        public override string DamageBlock(int Accuracy, CreatureBase AttackingCreatureBase, out bool parry)
        {
            parry = false;

            string Result = "";
            lock (this)
            {
                if (buffManager.IsStunned() == true)
                    return "";

                //Try dodge
                double dodge = AgilityTotal / 2;
                if (AgilityTotal / 2 > Accuracy / 4.00)
                    dodge = Accuracy / 4.00;

                if (GameHandler.random.Next(1, System.Convert.ToInt32(Math.Floor(dodge)) + Accuracy) <= dodge)
                    Result = "Dodge";

                if (Result == "")
                {
                    int LeftHandDefense = 0;
                    int RightHandDefense = 0;
                    int Range = 0;
                    Weapon leftHand = null;
                    Weapon rightHand = null;
                    if (LeftHand != null && LeftHand is Weapon)
                    {
                        leftHand = (Weapon)LeftHand;
                        if ((leftHand.Slot == "LeftHand" || leftHand.Slot == "EitherHand") && equipManager.MeetsRequirements(leftHand))
                        {
                            decimal skillLevelToUse = 0;

                            //Check if we're going to use shield mastery skill and apply our blunt skill to the weapon.
                            if (weaponSkillManager.useShieldMastery(leftHand) == true)
                            {
                                skillLevelToUse = Math.Floor(skillManager.GetCurrentLevel("Blunt_1H"));
                            }
                            else
                                skillLevelToUse = Math.Floor(skillManager.GetCurrentLevel(leftHand.Skill));

                            LeftHandDefense = SkillManager.AdjustForCombat(System.Convert.ToInt32(Math.Floor(skillLevelToUse)), leftHand.Defense, System.Convert.ToInt32(Math.Round(AgilityTotal / 2.00)), 4);
                        }
                        else
                            leftHand = null;
                    }
                    if (RightHand != null && RightHand is Weapon)
                    {
                        rightHand = (Weapon)RightHand;
                        if ((rightHand.Slot == "RightHand" || rightHand.Slot == "EitherHand" || (rightHand.Slot == "2Hand" && LeftHand == null)) && equipManager.MeetsRequirements(rightHand))
                        {
                            if (rightHand.Slot == "2Hand")
                                RightHandDefense = SkillManager.AdjustForCombat(System.Convert.ToInt32(Math.Floor(skillManager.GetCurrentLevel(rightHand.Skill))), rightHand.Defense, AgilityTotal, 2);
                            else
                                RightHandDefense = SkillManager.AdjustForCombat(System.Convert.ToInt32(Math.Floor(skillManager.GetCurrentLevel(rightHand.Skill))), rightHand.Defense, System.Convert.ToInt32(Math.Round(AgilityTotal / 2.00)), 4);
                        }
                        else
                            rightHand = null;
                    }
                    if (LeftHand == null && RightHand == null)
                    {
                        Weapon hand = new Weapon(GameHandler);
                        hand.Accuracy = 10;
                        hand.DmgLow = 8;
                        hand.DmgHigh = 12;
                        hand.Name = "Hand";
                        hand.StamCost = 20;
                        hand.Skill = "Hand";
                        hand.Melee = true;
                        hand.Speed = 3M;

                        rightHand = hand;
                        RightHandDefense = SkillManager.AdjustForCombat(System.Convert.ToInt32(Math.Floor(skillManager.GetCurrentLevel("Hand") / 2)), 10, AgilityTotal);
                    }
                    Range = Accuracy + LeftHandDefense + RightHandDefense;

                    int blockResult = GameHandler.random.Next(1, Range + 1);
                    if (blockResult > Accuracy)
                    {
                        if (LeftHandDefense > 0 && RightHandDefense > 0)
                        {
                            if (blockResult <= LeftHandDefense + Accuracy)
                            {
                                Result = leftHand.Name;
                                parry = weaponSkillManager.useParry(leftHand);
                            }
                            else if (blockResult > LeftHandDefense + Accuracy)
                            {
                                Result = rightHand.Name;
                                parry = weaponSkillManager.useParry(rightHand);
                            }
                        }
                        else if (LeftHandDefense > 0)
                        {
                            Result = leftHand.Name;
                            parry = weaponSkillManager.useParry(leftHand);
                        }
                        else
                        {
                            Result = rightHand.Name;
                            parry = weaponSkillManager.useParry(rightHand);
                        }
                    }
                } 
            }

            if (Result == "Dodge")
            {
                //Send message of block to this character
                Message blockMsg = new Message();
                blockMsg.CreatureID = this.CreatureID;
                blockMsg.Text = "You dodge " + AttackingCreatureBase.Name + "!";
                blockMsg.Type = "spelldefense";
                this.AddMessage(blockMsg);

                if (AttackingCreatureBase is Character)
                {
                    Character character = (Character)AttackingCreatureBase;
                    Message blockMsg1 = new Message();
                    blockMsg1.Type = "damage";
                    blockMsg1.CreatureID = character.CreatureID;
                    blockMsg1.Text = this.Name + " dodges!";
                    character.AddMessage(blockMsg1);
                }
            }
            else if (Result != "")
            {
                string blockedString = "blocked";
                if (parry == true)
                    blockedString = "parried";

                //Send message of block to this character
                Message blockMsg = new Message();
                blockMsg.CreatureID = this.CreatureID;
                blockMsg.Text = AttackingCreatureBase.Name + " is "+ blockedString + " by your " + Result + "!";
                blockMsg.Type = "spelldefense";
                this.AddMessage(blockMsg);

                if (AttackingCreatureBase is Character)
                {
                    Character character = (Character)AttackingCreatureBase;
                    Message blockMsg1 = new Message();
                    blockMsg1.Type = "damage";
                    blockMsg1.CreatureID = character.CreatureID;
                    blockMsg1.Text = "You are " + blockedString + " by " + this.Name + "\'s " + Result + "!";
                    character.AddMessage(blockMsg1);
                }
            }
            return Result;
        }

        //Auto selects weapon to attack with (not for range)
        public int AttackCreatureBase(CreatureBase CreatureToAttack, bool isRushAttack, out int Delay)
        {
            int attackSuccess = 0;
            if (RightHand is Weapon)
            {
                Weapon weapon = (Weapon)RightHand;
                if (weapon.Melee == true)
                {
                    if (((weapon.Slot == "RightHand" || weapon.Slot == "EitherHand") || (weapon.Slot == "2Hand" && LeftHand == null)) && equipManager.MeetsRequirements(weapon))
                        attackSuccess = AttackCreatureBase(CreatureToAttack, (Weapon)RightHand, false, false, isRushAttack, out Delay);
                    else
                        attackSuccess = AttackCreatureBase(CreatureToAttack, null, false, false, isRushAttack, out Delay);
                }
                else
                    attackSuccess = AttackCreatureBase(CreatureToAttack, null, false, false, isRushAttack, out Delay);
            }
            else if (RightHand == null)
            {
                Weapon hand = new Weapon(GameHandler);
                hand.Accuracy = 10;
                hand.DmgLow = 8;
                hand.DmgHigh = 12;
                hand.Name = "Hand";
                hand.StamCost = 20;
                hand.Skill = "Hand";
                hand.Melee = true;
                hand.Speed = 3M;
                attackSuccess = AttackCreatureBase(CreatureToAttack, hand, false, false, isRushAttack, out Delay);
            }
            else
            {
                attackSuccess = AttackCreatureBase(CreatureToAttack, null, false, false, isRushAttack, out Delay);
            }
            return attackSuccess;
        }
        public int AttackCreatureBase(CreatureBase CreatureToAttack, Weapon weapon, bool UseRange, bool isSecondary, bool isRushAttack, out int Delay)
        {
            int resultDamage = 0;

            //Secondary attacks like duel weild and double attack do not need to check SD flag, the primary already has.
            if (isSecondary == false)
            {
                //TODO: This logic should be moved into hateManager (multiple instances of this logic)

                //Get the creature we would give a SD flag to.
                Character characterToApplyFlag = null;

                //If the creature we're attacking is a pet, get its master
                Pet_Controller pc = CreatureToAttack.petController;
                //Has pet controller, check if master is character
                if (pc != null && pc.MasterCreature is Character)
                    characterToApplyFlag = (Character)pc.MasterCreature;
                //No pet controller, check if target is character
                else if (pc == null && CreatureToAttack is Character)
                    characterToApplyFlag = (Character)CreatureToAttack;

                //If we're attacking a player, and we dont have a flag on them, give them a flag on us.
                if (characterToApplyFlag != null &&
                    characterToApplyFlag != this &&
                    hateManager.GetCreatureHateInfo(characterToApplyFlag) == null)
                {
                    Character charToAttack = (Character)characterToApplyFlag;
                    if (charToAttack.friendsManager.hasNoSDFlag(ID) == false)
                    {
                        if (charToAttack.hateManager.GetCreatureHateInfo(this) == null)
                        {
                            charToAttack.SendMessage("You have been ATTACKED by " + this.Name + "!", "damaged");
                            charToAttack.PlaySound("Ding", charToAttack.MapX, charToAttack.MapY);

                            charToAttack.hateManager.UpdateList(this, 0);

                            charToAttack.AddMapItem(this.currentMapItem);
                        }
                        else
                            charToAttack.hateManager.UpdateList(this, 0);
                    }
                }
                /// End Hate Manager ////
            }

            //Flag used to reduce the attack & armor (like excessive force does when your blocked)
            double damageMultiplier = 1;
            if (isRushAttack == true)
            {
                Buff furiousRushBuff = buffManager.GetBuff("Furious Rush");
                if (furiousRushBuff != null)
                {
                    Spell_ExcessiveForce furiousRush = (Spell_ExcessiveForce)furiousRushBuff;
                    damageMultiplier = damageMultiplier * furiousRush.GetMultiplier();
                }
            }

            //Already checked by primary attack
            if (isSecondary == false)
            {
                Buff invis = buffManager.GetBuff("Invisibility");
                if (invis != null) invis.RemoveSpell(true, true);
            }

            bool usePerfect = weaponSkillManager.usePerfectSwing(weapon);

            Delay = 3000;
            int Atk = GameHandler.random.Next(1, 10 + 1);
            int Acc = 10;
            int StamCost = 20;

            if (weapon != null)
                StamCost = weapon.StamCost;

            string skillToUse = "";

            if (weapon != null && StamCost <= Stamina)
            {
                skillToUse = weapon.Skill;
                if (UseRange == true && skillToUse == "")
                    skillToUse = "Range";

                if (usePerfect == false)
                    Atk = GameHandler.random.Next(weapon.DmgLow, weapon.DmgHigh + 1);
                else
                    Atk = weapon.DmgHigh;

                if (skillToUse == "Range")
                    Atk = skillManager.AdjustForCombat(skillToUse, Atk, DexterityTotal);
                else
                    Atk = skillManager.AdjustForCombat(skillToUse, Atk, StrengthTotal);

                Delay = (int)(weapon.Speed * 1000);
                if (MeleeSpeedPercentModifier != 0 && UseRange == false)
                {
                    decimal reduceBy = System.Convert.ToDecimal(Delay) * System.Convert.ToDecimal((MeleeSpeedPercentModifier / 100.00));
                    Delay = Delay + System.Convert.ToInt32(Math.Floor(reduceBy));
                }
                else if (RangeSpeedPercentModifier != 0 && UseRange == true)
                {
                    decimal reduceBy = System.Convert.ToDecimal(Delay) * System.Convert.ToDecimal((RangeSpeedPercentModifier / 100.00));
                    Delay = Delay + System.Convert.ToInt32(Math.Floor(reduceBy));
                }
                Acc = skillManager.AdjustForCombat(skillToUse, weapon.Accuracy, DexterityTotal);
            }
            //Stop everything if we're out of stamina
            else if (StamCost > Stamina)
            {
                Delay = 3000;

                //Do not send messages for out of stam on secondary, just dont perform the attack.
                if (isSecondary == false)
                {
                    this.SendMessage("You do not have enough stamina!", "server");
                    this.PlaySound("Ding", this.MapX, this.MapY);
                }
                //Do not penalize for out of stam on a secondary attack, just return no delay
                else
                    Delay = 0;
                

                return 0;
            }

            Stamina = Stamina - StamCost;

            List<Character> charactersWithin8 = CreatureToAttack.currentMapItem.getCharactersWithin8();

            

            if (usePerfect == false)
            {
                //Check for miss
                int totalForMiss = 10 + Acc;
                if (GameHandler.random.Next(1, totalForMiss + 1) < 11)
                {
                    foreach (Character character in charactersWithin8)
                    {
                        if (UseRange == true)
                            character.PlaySound("ArrowMiss", MapX, MapY);
                        else
                            character.PlaySound("SwingMiss", MapX, MapY);
                    }

                    Message msg = new Message();
                    msg.CreatureID = CreatureID;
                    msg.Type = "damage";
                    msg.Text = "You miss " + CreatureToAttack.Name;

                    AddMessage(msg);

                    if (CreatureToAttack is Character)
                    {
                        Character character = (Character)CreatureToAttack;

                        Message msg1 = new Message();
                        msg1.CreatureID = character.CreatureID;
                        msg1.Type = "damaged";
                        msg1.Text = this.Name + " misses you";
                        character.AddMessage(msg1);
                    }
                    if (CreatureToAttack is Creature)
                        CreatureToAttack.hateManager.UpdateList(this, 0);

                    resultDamage = -1;
                }
            }

            //If we've missed, dont do any of this (will = -1 if we've missed)
            if (resultDamage == 0)
            {
                //Flag used incase we play the block sound but still do damage
                bool skipHitSound = false;


                bool blockAll = false;

                if (usePerfect == false)
                {
                    bool parry;
                    string blockedBy = CreatureToAttack.DamageBlock(Acc, this, out parry);

                    if (blockedBy == "Dodge")
                    {
                        foreach (Character character in charactersWithin8)
                        {
                            character.PlaySound("SwingMiss", MapX, MapY);
                        }

                        resultDamage = -1;
                        blockAll = true;
                    }
                    else if (blockedBy != "")
                    {
                        foreach (Character character in charactersWithin8)
                        {
                            if (UseRange == false)
                            {
                                if (Math.Abs(character.MapX - CreatureToAttack.MapX) <= 8 && Math.Abs(character.MapY - CreatureToAttack.MapY) <= 8)
                                    character.PlaySound("SwingBlockNonMetal", CreatureToAttack.MapX, CreatureToAttack.MapY);
                            }
                            else
                            {
                                if (Math.Abs(character.MapX - CreatureToAttack.MapX) <= 8 && Math.Abs(character.MapY - CreatureToAttack.MapY) <= 8)
                                    character.PlaySound("ArrowBlockNonMetal", CreatureToAttack.MapX, CreatureToAttack.MapY);
                            }
                        }

                        if (parry == true)
                        {
                            Delay = Delay * 2;
                        }

                        if (UseRange == false && weapon != null)
                        {
                            if (weaponSkillManager.useExcessiveForce(weapon) == true)
                            {
                                damageMultiplier = damageMultiplier * .5;
                            }
                            else
                                blockAll = true;

                            //Buff excessiveForceBuff = buffManager.GetBuff("Excessive Force");
                            //if (excessiveForceBuff != null)
                            //{
                            //    Spell_ExcessiveForce excessiveForce = (Spell_ExcessiveForce)excessiveForceBuff;
                            //    damageMultiplier = damageMultiplier * excessiveForce.GetMultiplier();
                            //    skipHitSound = true;
                            //}
                            //else
                            //    blockAll = true;
                        }
                        else
                            blockAll = true;
                    }
                }

                //If we were blocked, dont do any of this
                if (blockAll == false)
                {
                    //Try for critical
                    bool useCritical = weaponSkillManager.useCriticalDamage(weapon);
                    if (useCritical == true)
                        Atk = Atk * 2;

                    bool useStun = weaponSkillManager.useStunningBlow(weapon);
                    if (CreatureToAttack is Creature)
                    {
                        Creature creatureToAttack = (Creature)CreatureToAttack;
                        if (creatureToAttack.isImmune("Stun") == true)
                            useStun = false;
                    }

                    string criticalMsg = "";
                    if (useCritical)
                        criticalMsg = " Critical!";
                    if (usePerfect)
                        criticalMsg = criticalMsg + " Perfect!";
                    if (useStun)
                        criticalMsg = criticalMsg + " Stun!";

                    int armorPiercing = weaponSkillManager.useArmorPiercing(weapon);

                    //Calculates damage after armor, reduces HP, sends messages, notifys hate list
                    int damageAbsorbed;
                    resultDamage = CreatureToAttack.InflictDamageArmorReduce(Atk, this, out damageAbsorbed, UseRange, damageMultiplier, armorPiercing);

                    if (useStun)
                    {
                        Spell_Stun stunSpell = new Spell_Stun();
                        SpellIcon stunIcon = Managers.GameHandler.getSpellByName("Stun");

                        stunSpell.Resume(CreatureToAttack, stunIcon, 2, System.Convert.ToInt32(Math.Floor(skillManager.GetCurrentLevel(skillToUse))), this.ID, this.IntelligenceTotal, this.WisdomTotal, -1, null);
                    }

                    //Check for a weapon effect (Currently only poison)
                    if (weapon != null && weapon.WeaponEffect != null && resultDamage > 0 && CreatureToAttack.HP > 0)
                    {
                        Spell_PoisonBuff buff = new Spell_PoisonBuff();
                        buff.InstantCast(this, CreatureToAttack, weapon.WeaponEffect.clone(), weapon.WeaponEffectLevel);
                        //buff.Resume(CreatureToAttack, weapon.WeaponEffect.clone(), -1, weapon.WeaponEffectLevel, ID, weapon.WeaponEffectInt, weapon.WeaponEffectWis, -1);

                        weapon.WeaponEffect = null;
                        Update_Character();
                    }

                    //Send damage message
                    Message message = new Message();
                    message.CreatureID = CreatureID;
                    message.Type = "damage";

                    string dmgDescription1 = "hit";
                    string dmgDescription2 = "hits";

                    if (weapon != null && UseRange == true && weapon.RangeThrows == false)
                    {
                        dmgDescription1 = "shoot";
                        dmgDescription2 = "shoots";
                    }
                    else if (weapon != null)
                    {
                        if (weapon.Skill.ToLower().IndexOf("slashing") > -1)
                        {
                            dmgDescription1 = "slash";
                            dmgDescription2 = "slashes";
                        }
                        else if (weapon.Skill.ToLower().IndexOf("piercing") > -1)
                        {
                            dmgDescription1 = "pierce";
                            dmgDescription2 = "pierces";
                        }
                        else if (weapon.Skill.ToLower().IndexOf("blunt") > -1)
                        {
                            dmgDescription1 = "strike";
                            dmgDescription2 = "strikes";
                        }
                        else if (weapon.Skill.ToLower().IndexOf("hand") > -1)
                        {
                            dmgDescription1 = "punch";
                            dmgDescription2 = "punches";
                        }
                    }

                    if (damageAbsorbed > 0)
                        message.Text = "You " + dmgDescription1 + " " + CreatureToAttack.Name + " (" + resultDamage.ToString() + criticalMsg + ") ABSORBED " + damageAbsorbed.ToString();
                    else
                        message.Text = "You " + dmgDescription1 + " " + CreatureToAttack.Name + " (" + resultDamage.ToString() + criticalMsg + ")";

                    AddMessage(message);

                    if (CreatureToAttack is Character)
                    {
                        Character charToAttack = (Character)CreatureToAttack;

                        Message msg = new Message();
                        msg.CreatureID = charToAttack.CreatureID;
                        msg.Type = "damaged";

                        if (damageAbsorbed > 0)
                            msg.Text = this.Name + " " + dmgDescription2 + " you (" + resultDamage.ToString() + criticalMsg + ") ABSORBED " + damageAbsorbed.ToString();
                        else
                            msg.Text = this.Name + " " + dmgDescription2 + " you (" + resultDamage.ToString() + criticalMsg + ")";

                        charToAttack.AddMessage(msg);
                    }

                    //Add Exp
                    if (weapon != null && CreatureToAttack.grantExpTo(this) == true && resultDamage < CreatureToAttack.MaxHP * .8)
                    {
                        decimal exp = System.Convert.ToDecimal(Delay);
                        exp = exp / 1000;

                        skillManager.AddExp(skillToUse, exp);
                    }

                    //Check if this is a rush attack, look for an instant rush ability, remove the delay
                    if (isRushAttack == true)
                    {
                        if (weaponSkillManager.useInstantRush(weapon) == true)
                            Delay = 1;
                    }

                    if (skipHitSound == false)
                    {
                        //Play Hit Sound
                        string soundName = "SwingHitSevere";

                        int medium = CreatureToAttack.MaxHP - System.Convert.ToInt32(CreatureToAttack.MaxHP * .72);
                        if (CreatureToAttack.HP > medium)
                            soundName = "SwingHitModerate";

                        int light = CreatureToAttack.MaxHP - System.Convert.ToInt32(CreatureToAttack.MaxHP * .28);
                        if (CreatureToAttack.HP > light)
                            soundName = "SwingHitLight";

                        if (UseRange == true)
                        {
                            soundName = soundName.Replace("Swing", "Arrow");
                        }
                        foreach (Character character in charactersWithin8)
                        {
                            if (Math.Abs(character.MapX - CreatureToAttack.MapX) <= 8 && Math.Abs(character.MapY - CreatureToAttack.MapY) <= 8)
                                character.PlaySound(soundName, CreatureToAttack.MapX, CreatureToAttack.MapY);
                        }
                    }

                    if (CreatureToAttack.HP < 1)
                    {
                        if (CreatureToAttack is Character)
                        {
                            Character character = (Character)CreatureToAttack;

                            //Send Slain Message
                            Message msgSlain = new Message();
                            msgSlain.CreatureID = character.CreatureID;
                            msgSlain.Text = "You have been SLAIN by " + this.Name + "!";
                            msgSlain.Type = "slain";

                            //Add message to update
                            character.AddMessage(msgSlain);
                        }

                        Message msgSlay = new Message();
                        msgSlay.CreatureID = this.CreatureID;
                        msgSlay.Type = "damage";
                        msgSlay.Text = "You have slain " + CreatureToAttack.Name + "!";
                        AddMessage(msgSlay);
                    }
                }
            }

            if (isSecondary == false)
            {
                int secondaryDelay = 0;
                int secondaryDamage = 0;

                if (UseRange == false && CreatureToAttack.HP > 0)
                {
                    Weapon dualWeildWeapon = weaponSkillManager.getDualWeildWeapon(weapon);
                    if (dualWeildWeapon != null)
                    {
                        secondaryDamage = AttackCreatureBase(CreatureToAttack, dualWeildWeapon, false, true, isRushAttack, out secondaryDelay);
                        resultDamage = resultDamage + secondaryDamage;

                        if (secondaryDelay > Delay)
                            Delay = secondaryDelay;
                    }
                }
                //Check for double attack
                if ((CreatureToAttack.HP > 0 && UseRange == false) ||
                    (CreatureToAttack.HP > 0 && UseRange == true && weapon.Melee == false))
                {
                    bool useDoubleAttack = weaponSkillManager.useDoubleAttackSkill(weapon);
                    if (useDoubleAttack == true)
                    {
                        secondaryDamage = AttackCreatureBase(CreatureToAttack, weapon, UseRange, true, isRushAttack, out secondaryDelay);
                        resultDamage = resultDamage + secondaryDamage;

                        if (secondaryDelay > Delay)
                            Delay = secondaryDelay;
                    }
                }
                if (UseRange == false && isRushAttack == false && weapon != null)
                {
                    Buff excessiveForceBuff = buffManager.GetBuffByStackType("Frenzy");
                    if (excessiveForceBuff != null)
                    {
                        Spell_ExcessiveForce frenzyBuff = (Spell_ExcessiveForce)excessiveForceBuff;
                        
                        List<CreatureBase> attackableCreatures = new List<CreatureBase>();
                        foreach (CreatureBase creatureBase in currentMapItem.CreaturesBases)
                        {
                            if ((creatureBase.Faction != Faction || hateManager.GetCreatureHateInfo(creatureBase) != null) &&
                                creatureBase.CanSeeMe(this) &&
                                creatureBase.HP > 0 &&
                                creatureBase != CreatureToAttack)
                            {
                                attackableCreatures.Add(creatureBase);
                            }
                        }

                        //Increment the spells counter
                        if (attackableCreatures.Count > 0)
                            frenzyBuff.GetMultiplier();

                        int dummyDelay;
                        int creatureCount = 0;
                        while (creatureCount < 1 && attackableCreatures.Count > 0)
                        {
                            creatureCount++;

                            int randomIndex = Managers.GameHandler.random.Next(0, attackableCreatures.Count);
                            CreatureBase randomCreature = attackableCreatures[randomIndex];

                            attackableCreatures.RemoveAt(randomIndex);


                            secondaryDamage = AttackCreatureBase(randomCreature, weapon, false, true, false, out dummyDelay);
                            resultDamage = resultDamage + secondaryDamage;

                            if (secondaryDamage > 0)
                            {
                                foreach (Character character in charactersWithin8)
                                {
                                    if (Math.Abs(character.MapX - currentMapItem.MapX) <= 4 && Math.Abs(character.MapY - currentMapItem.MapY) <= 4)
                                    {
                                        if (randomCreature.HP < 1)
                                            character.AddMapItem(currentMapItem);
                                        else
                                            character.AddCreatureBase(randomCreature);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Update_Character();
            foreach (Character character in charactersWithin8)
            {
                if (Math.Abs(character.MapX - MapX) <= 4 && Math.Abs(character.MapY - MapY) <= 4)
                    character.UpdateCreatureBaseStamina(this);
            }

            return resultDamage;
        }

        //Counds the number of occurances of the itemId specified. Item must be bound to me, or unbound (-1)
        public int countInventory(int itemId, bool includeBank)
        {
            int result = 0;

            result = result + bagManager.countItems(itemId);
            result = result + beltManager.countItems(itemId);

            Loot leftHandItem = LeftHand;
            if (leftHandItem != null &&
                leftHandItem.ID == itemId &&
                (leftHandItem.BoundTo == -1 || leftHandItem.BoundTo == ID))
            {
                result++;
            }

            Loot rightHandItem = RightHand;
            if (rightHandItem != null &&
                rightHandItem.ID == itemId &&
                (rightHandItem.BoundTo == -1 || rightHandItem.BoundTo == ID))
            {
                result++;
            }

            if (includeBank)
            {
                result = result + bankManager.countItems(itemId);
            }

            return result;
        }

        //Used for checking for lore items (Checks Equipment being worn & all inventory)
        public bool hasItem(int itemId)
        {
            if (equipManager.hasItem(itemId))
                return true;
            if (bagManager.hasItem(itemId))
                return true;
            if (beltManager.hasItem(itemId))
                return true;

            Loot leftHandItem = LeftHand;
            if (leftHandItem != null && leftHandItem.ID == itemId)
                return true;

            Loot rightHandItem = RightHand;
            if (rightHandItem != null && rightHandItem.ID == itemId)
                return true;

            return false;
        }

        //Scans inventory for collection items, returns list of items or null if incomplete
        //Currently used for mailing attachements (User specifies itemGUIDs)
        public List<Loot> getInventoryItems(List<long> itemGUIDs)
        {
            List<Loot> result = new List<Loot>();

            foreach (long guid in itemGUIDs)
            {
                Loot leftHandItem = LeftHand;
                if (leftHandItem != null && leftHandItem.GameUID == guid)
                {
                    result.Add(leftHandItem);
                    continue;
                }

                Loot rightHandItem = RightHand;
                if (rightHandItem != null && rightHandItem.GameUID == guid)
                {
                    result.Add(rightHandItem);
                    continue;
                }

                Loot[] beltItems = beltManager.getBeltLootCopy();
                bool foundInBelt = false;
                for (int x = 0; x < beltItems.Length; x++)
                {
                    Loot beltLoot = beltItems[x];
                    if (beltLoot != null && beltLoot.GameUID == guid)
                    {
                        result.Add(beltLoot);
                        foundInBelt = true;
                        break;
                    }
                }
                if (foundInBelt == true)
                    continue;

                Loot bagItem = bagManager.getBagItem(guid);
                if (bagItem != null)
                {
                    result.Add(bagItem);
                    continue;
                }

                return null;
            }

            return result;
        }

        public void RemoveFromInventory(List<Loot> Items, out bool updateBag, out bool updateBelt, out bool updateCharacter)
        {
            RemoveFromInventory(Items, out updateBag, out updateBelt, out updateCharacter, false);
        }
        public void RemoveFromInventory(List<Loot> Items, out bool updateBag, out bool updateBelt, out bool updateCharacter, bool includeBank)
        {
            updateBag = false;
            updateBelt = false;
            updateCharacter = false;

            foreach (Loot loot in Items)
            {
                if (LeftHand != null && LeftHand.GameUID == loot.GameUID)
                {
                    updateCharacter = true;
                    LeftHand = null;
                    continue;
                }
                if (RightHand != null && RightHand.GameUID == loot.GameUID)
                {
                    updateCharacter = true;
                    RightHand = null;
                    continue;
                }
                if (bagManager.removeBagItem(loot.GameUID) != null)
                {
                    updateBag = true;
                    continue;
                }
                if (beltManager.RemoveBeltItem(loot.GameUID) != null)
                {
                    updateBelt = true;
                    continue;
                }
                if (includeBank)
                {
                    bankManager.removeItem(loot);
                    continue;
                }
            }
        }

        public void AddToInventory(List<Loot> Items, out bool updateBag, out bool updateBelt, out bool updateCharacter)
        {
            AddToInventory(Items, out updateBag, out updateBelt, out updateCharacter, false);
        }
        //Adds noBinding parameter. Used for GM activities such as conjure items where we're adding it to our inventory but do not want it to bind. 
        public void AddToInventory(List<Loot> Items, out bool updateBag, out bool updateBelt, out bool updateCharacter, bool noBinding)
        {
            updateBag = false;
            updateBelt = false;
            updateCharacter = false;

            foreach (Loot loot in Items)
            {
                if (loot.BoundTo < -1 && noBinding == false)
                    loot.BoundTo = ID;

                if (loot.Bag == true && bagManager.addBagItem(loot) == true)
                {
                    updateBag = true;
                    continue;
                }
                if (loot.Belt == true && beltManager.AddItem(loot) == true)
                {
                    updateBelt = true;
                    continue;
                }
                if (LeftHand == null)
                {
                    LeftHand = loot;
                    updateCharacter = true;
                    continue;
                }
                if (RightHand == null)
                {
                    RightHand = loot;
                    updateCharacter = true;
                    continue;
                }
            }
        }

        public bool HasInventoryFor(List<Loot> Items)
        {
            //Check if we have inventory for the quest rewards
            bool hasInventory = true;

            int bagSlots = bagManager.SlotsAvailable();
            int beltSlots = beltManager.SlotsAvailable();
            bool leftHandAvailable = LeftHand == null;
            bool rightHandAvailable = RightHand == null;
            foreach (Loot loot in Items)
            {
                if (loot.Bag == true && bagSlots > 0)
                {
                    bagSlots--;
                    continue;
                }
                if (loot.Belt == true && beltSlots > 0)
                {
                    beltSlots--;
                    continue;
                }
                if (leftHandAvailable)
                {
                    leftHandAvailable = false;
                    continue;
                }
                if (rightHandAvailable)
                {
                    rightHandAvailable = false;
                    continue;
                }

                hasInventory = false;
                break;
            }

            return hasInventory;
        }
       
    }
}
